/**
 * Created by oneminute on 2014/4/24.
 */

var lz = require("../lib/utils/modules")();
var path = require("path");
var fs = require("fs");

var filtersMap = null;
var baseDir = null;

exports.setup = function (_app) {

    lz.Logger.info("注册请求路径。");

    filtersMap = Object.create(null);
    baseDir = lz.Config.routes.basePath;

    lz.Config.routes.filters.forEach(function (_filter) {
        filtersMap[_filter.name] = _filter;
        _filter.fn = require(baseDir + _filter.module);
    });

    lz.Config.routes.paths.forEach(exports.__registerPath.bind(null, _app));
};

exports.__registerPath = function (_app, _path) {
    if (_path.filters) {
        _path.filters.forEach(function (_filter) {
            var filter = filtersMap[_filter];
            //_app.all(_path.path, filter.fn);
            var route = _app.route(_path.path).all(filter.fn);
            _path.methods.forEach(exports.__registerMethod.bind(null, route, _path));
        });
    } else {
        var route = _app.route(_path.path);
        _path.methods.forEach(exports.__registerMethod.bind(null, route, _path));
    }
};

exports.__registerMethod = function (_app, _path, _method) {
    var route = require(baseDir + _path.module);
    var method = _method.toLowerCase();
    _app[method](function (_req, _res, _next) {
        lz.Logger.info("%s: 用户(%s, %s)发起请求。", _path.path, _req.query.uid, _req.user ? _req.user.name : "临时");
        _req.lzRoute = _path;
        var opts = {};
        if (_path.template) {
            opts.template = _path.template;
        }
        opts.user = _req.user;
        var result = {};
        var err = exports.__checkParams(_req, _path.params, opts);
        if (err) {
            lz.Logger.error("route:route: 参数验证失败。");
            result.res = err.message;
            result.code = err.code;
            result.err = err.err;
            result.uid = _req.query.uid;
            _res.json(result);
        } else {
            route[method](_req, _res, opts, function (_err, _user, _args, _isEnd) {
                result.uid = _req.query.uid;
                if (_user && _user.hasOwnProperty("id")) {
                    result.uid = _user.id;
                }
                if (result.uid)
                    result.uid = lz.Utils.encrypt(result.uid);
                if (_err) {
                    result.res = _err.message;
                    result.error = _err.code;
                } else {
                    if (opts.template) {
                        _res.render(opts.template, _args);
                        return;
                    } else {
                        result.res = "ok";
                        if (_args) {
                            if (Array.isArray(_args)) {
                                result.array = _args;
                                if (arguments.length == 4) {
                                    result.isEnd = _isEnd;
                                } else {
                                    if (_args.length > 0) {
                                        result.isEnd = false;
                                    } else {
                                        result.isEnd = true;
                                    }
                                }
                            } else {
                                result.object = _args;
                                result.isEnd = true;
                            }
                        }
                    }
                }
                lz.Logger.debug("response: ", {
                    res: result.res,
                    uid: result.uid,
                    error: result.error,
                    object: result.object,
                    array: result.array ? result.array.length : null,
                    isEnd: result.isEnd
                });
                if (_args && _args.redirect) {
                    _res.redirect(_args.url);
                }
                _res.json(result);
            });
        }
    });
};

exports.__checkParams = function (_req, _params, _opts) {
    for (var i = 0; _params && i < _params.length; i++) {
        var param = _params[i];
        if (param.require) {
            if (!_req[param.from] || !_req[param.from][param.name]) {
                lz.Logger.error("route:__checkParams: 缺失参数。", param.name);
                return lz.Config.errors.getError(lz.Config.errors.REQUEST_MISS_PARAMETER, param.name);
            }
        }

        var reqParam = _req[param.from][param.name];
        var value = null;
        try {
            switch (param.type) {
                case "float":
                    value = parseFloat(reqParam);
                    break;
                case "int":
                    value = parseInt(reqParam);
                    break;
                case "boolean":
                    value = reqParam == "true";
                    break;
                case "string":
                    value = reqParam;
                    break;
                case "file":
                    value = reqParam;
                    break;
                case "array":
                    value = reqParam;
                    break;
                case "object":
                    value = reqParam;
                    break;
                default:
                    throw "invalide parameter type";
            }
        } catch (_exception) {
            return lz.Config.errors.getError(lz.Config.errors.REQUEST_PARAMETER_INVALIDATE_TYPE, param.name);
        }

        lz.Logger.debug("checkParams: param:%s value:%s", param.name, value);
        if (param.hasOwnProperty('default')) {
            value = value || param.default;
        }

        if (param.rule) {
            var rule = param.rule;
            switch (rule) {
                case "range":
                {
                    if (value < rule.from || value > rule.to) {
                        return lz.Config.errors.getError(lz.Config.errors.REQUEST_PARAMETER_INVALIDATE_VALUE, param.name);
                    }
                    break;
                }
                case "values":
                {
                    if (rule.values.indexOf(value) < 0) {
                        return lz.Config.errors.getError(lz.Config.errors.REQUEST_PARAMETER_INVALIDATE_VALUE, param.name);
                    }
                    break;
                }
            }
        }

        _opts[param.name] = value;
    }
    return null;
};
